﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////


#include "GnufAppearanceSetting.h"
#include "GnufArrangementArea.h"
#include "GnufArrangementAreaEvents.h"
#include "GnufBoolValueInput.h"
#include "GnufBoolValueInputGroup.h"
#include "GnufCheck.h"
#include "GnufCheckGroup.h"
#include "GnufCheckListButton.h"
#include "GnufCheckListValueInput.h"
#include "GnufList.h"
#include "GnufListValueInput.h"
#include "GnufNameValuePairs.h"
#include "GnufPreferenceEntries.h"
#include "GnufPreferences.h"
#include "GnufQtToolbar.h"
#include "GnufText.h"
#include "GnufTextValueInput.h"
#include "GnufToolbar.h"
#include "GnufUtility.h"
#include "GnufValueInputSet.h"
#include "GnufWidgetAgent.h"
#include "GnufWidgetAgentValueInput.h"
#include "GnufListWidget.h"
#include "GnufListWidgetInput.h"
#include "MultisectionLoftEditModePanel.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gnuf;
using namespace gfam;

namespace gfam
{
    class NameValuePairsBuilder
    {
    public:
        NameValuePairsBuilder(NameValuePairs* nvps)
            : m_nvps(nvps)
        {}

        void build(ValueInputSet* valueInputSet) 
        {
            build(valueInputSet->rawContents(), nullptr);
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps != nullptr, L"m_nvps is null", L"paramodel", L"2024-02-20");
            m_nvps->dumpContents();
        }

    private:
        void build(const std::vector< ValueInputBase*>&, NameValuePairBlock*);
        void build(BoolValueInput*, NameValuePairBlock*);
        void build(TextValueInput*, NameValuePairBlock*);
        void build(BoolValueInputGroup*, NameValuePairBlock*);
        void build(ListValueInput*, NameValuePairBlock*);
        void build(CheckListValueInput*, NameValuePairBlock*);
        void build(WidgetAgentValueInput*, NameValuePairBlock*);
        void build(ListWidgetInput*, NameValuePairBlock*);

    private:
        NameValuePairs* m_nvps;
    };

    void NameValuePairsBuilder::build(const std::vector< ValueInputBase*>& ones, NameValuePairBlock* nvpb)
    {
        for (auto one : ones)
        {
            if (BoolValueInput* boolValueInput = gcmp::quick_cast<BoolValueInput>(one))
            {
                build(boolValueInput, nvpb);
            }
            else if (TextValueInput* textValueInput = gcmp::quick_cast<TextValueInput>(one))
            {
                build(textValueInput, nvpb);
            }
            else if (ListValueInput* listValueInput = gcmp::quick_cast<ListValueInput>(one))
            {
                build(listValueInput, nvpb);
            }
            else if (CheckListValueInput* listValueInput = gcmp::quick_cast<CheckListValueInput>(one))
            {
                build(listValueInput, nvpb);
            }
            else if (BoolValueInputGroup* boolValueInputGroup = gcmp::quick_cast<BoolValueInputGroup>(one))
            {
                build(boolValueInputGroup, nvpb);
            }
            else if (WidgetAgentValueInput* wgtValueInput = gcmp::quick_cast<WidgetAgentValueInput>(one))
            {
                build(wgtValueInput, nvpb);
            }
            else if (ListWidgetInput* listWidgetInput = gcmp::quick_cast<ListWidgetInput>(one))
            {
                build(listWidgetInput, nvpb);
            }
            else if (ValueInputGroup* valueInputGroup = gcmp::quick_cast<ValueInputGroup>(one))
            {
                if (nullptr == nvpb)
                {
                    DBG_WARN_AND_CONTINUE_UNLESS(valueInputGroup->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
                    Info info(valueInputGroup->info());
                    DBG_WARN_AND_CONTINUE_UNLESS(m_nvps != nullptr, L"m_nvps is null", L"paramodel", L"2024-02-20");
                    nvpb = m_nvps->addNameValuePairBlock(info, true);
                    build(valueInputGroup->rawContents(), nvpb);
                }
                else
                {
                    // Cannot add a sub-one in a group.
                    GBMP_ASSERT(false);
                }
            }
            else {
                GBMP_ASSERT(false);
            }
        }
    }

    void NameValuePairsBuilder::build(BoolValueInput* input, NameValuePairBlock* nvpb)
    {
        CheckControl* pControl = input->checkControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");

        Info info(pControl->info());
        //
        // Add a check.
        Check* check = nullptr;
        if (nullptr == nvpb) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            check = m_nvps->addItem<Check>(info);
        }
        else {
            check = nvpb->addItem<Check>(info);
        }

        //
        // Initialize the value.
        check->setCheckState(input->value() ? CheckStatus::Checked : CheckStatus::UnChecked);
        check->setEnabled(pControl->isEnabled());

        if (check->parent() != nullptr)
        {
            check->setQtObjectName(gcmp::StringUtil::ToWString(check->parent()->path().str()) + L"/" + info.caption());
        }

        //
        // Subscribe to the check control.
        pControl->subscribe(check);
    }

    void NameValuePairsBuilder::build(TextValueInput* input, NameValuePairBlock* nvpb)
    {
        TextControl* pControl = input->textControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");

        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        //
        // Add a text.
        Text* text = nullptr;
        if (nullptr == nvpb) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            text = m_nvps->addItem<Text>(info);
        }
        else {
            text = nvpb->addItem<Text>(info);
        }

        //
        // Initialize the value.
        text->setText(input->value());
        text->setEnabled(pControl->isEnabled());

        if (text->parent() != nullptr)
        {
            text->setQtObjectName(gcmp::StringUtil::ToWString(text->parent()->path().str()) + L"/" + info.caption());
        }

        //
        // Subscribe to the text control.
        pControl->subscribe(text);
    }

    void NameValuePairsBuilder::build(BoolValueInputGroup* inputGroup, NameValuePairBlock* pBlock)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(inputGroup, L"inputGroup is nullptr", L"paramodel", L"2024-02-20");
        CheckGroupControl* pControl = inputGroup->checkGroupControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        // Add a checkGroup.
        CheckGroup* checkGroup = nullptr;
        if (nullptr == pBlock) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            checkGroup = m_nvps->addItem<CheckGroup>(info);
        }
        else {
            checkGroup = pBlock->addItem<CheckGroup>(info);
        }

        //
        // Initialize the value.
        std::vector<const Info*> rawList;
        pControl->GetList(rawList);
        FOR_EACH(item, rawList)
        {
            gcmp::OwnerPtr<Info> info = NEW_AS_OWNER_PTR(Info, item);
            checkGroup->AddItem(info);
        }
        const std::vector<bool>& checkStatus = pControl->GetCheckStatus();
        FOR_EACH_INDEX(index, checkStatus)
        {
            checkGroup->SetCheckStatus(index, checkStatus[index]);
        }
        checkGroup->SetExclusive(inputGroup->IsExclusive());
        checkGroup->setEnabled(pControl->isEnabled());
        if (checkGroup->parent() != nullptr)
        {
            checkGroup->setQtObjectName(gcmp::StringUtil::ToWString(checkGroup->parent()->path().str()) + L"/" + info.caption());
        }
        //
        // Subscribe to the checkGroup control.
        pControl->subscribe(checkGroup);
    }

    void NameValuePairsBuilder::build(ListValueInput* input, NameValuePairBlock* pBlock)
    {
        ListControl* pControl = input->listControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");

        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        // Add a List.
        List* pList = nullptr;
        if (nullptr == pBlock) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            pList = m_nvps->addItem<List>(info);
        }
        else {
            pList = pBlock->addItem<List>(info);
        }

        //
        // Initialize the value.
        FOR_EACH(item, pControl->GetList())
        {
            gcmp::OwnerPtr<Info> info = NEW_AS_OWNER_PTR(Info, item.get());
            pList->AddItem(info);
        }
        pList->SetSelectedIndex(input->value());
        pList->setEnabled(pControl->isEnabled());
        if (pList->parent() != nullptr)
        {
            pList->setQtObjectName(gcmp::StringUtil::ToWString(pList->parent()->path().str()) + L"/" + info.caption());
        }
        //
        // Subscribe to the list control.
        pControl->subscribe(pList);
    }

    void NameValuePairsBuilder::build(CheckListValueInput* input, NameValuePairBlock* pBlock)
    {
        CheckListControl* pControl = input->listControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");

        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        // Add a Check List.
        CheckListButton* pCheckListButton = nullptr;
        if (nullptr == pBlock) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            pCheckListButton = m_nvps->addItem<CheckListButton>(info);
        }
        else {
            pCheckListButton = pBlock->addItem<CheckListButton>(info);
        }

        //
        // Initialize the value.
        FOR_EACH(item, pControl->getList())
        {
            Info info(item.get());
            pCheckListButton->addItem(info, false);
        }

        const std::vector<bool>& checkStatus = pControl->getCheckStatus();
        FOR_EACH_INDEX(index, checkStatus)
        {
            pCheckListButton->setItemStatus(index, checkStatus.at(index));
        }

        // Config the check list.
        ICheckListControlHandler* pHandler = static_cast<ICheckListControlHandler*>(pControl->inputControlHandler());
        DBG_WARN_AND_RETURN_VOID_UNLESS(pHandler, L"pHandler is nullptr", L"paramodel", L"2024-02-20");

        const ICheckListControlAdaptationOption* pOption = pHandler->onGetListControlAdaptationOption();
        if (pOption)
        {
            if (const CheckListValueInputOption* pValueInputOption = dynamic_cast<const CheckListValueInputOption*>(pOption))
            {
                pCheckListButton->enableSelectAll(pValueInputOption->SelectAllEnable, pValueInputOption->SelectAllCaption);

                FOR_EACH_INDEX(index, checkStatus)
                {
                    pCheckListButton->setItemEnabled(index, pValueInputOption->EnableList.at(index));
                }

                if (pCheckListButton->dropDownBoard())
                {
                    if (pValueInputOption->ListCommitPolicy == CheckListValueInputOption::eOneShot)
                        pCheckListButton->dropDownBoard()->setCloseOnClick(true);
                    else if (pValueInputOption->ListCommitPolicy == CheckListValueInputOption::eNonDropDownAreaButtonPress)
                        pCheckListButton->dropDownBoard()->setCloseOnClick(false);
                }
            }
        }

        pCheckListButton->setEnabled(pControl->isEnabled());
        if (pCheckListButton->parent() != nullptr)
        {
            pCheckListButton->setQtObjectName(gcmp::StringUtil::ToWString(pCheckListButton->parent()->path().str()) + L"/" + info.caption());
        }
        //
        // Subscribe the drop down board to drop down board control.
        if (pControl->dropdownMenuControl())
        {
            pControl->dropdownMenuControl()->subscribe(pCheckListButton->dropDownBoard());
        }
    }

    void NameValuePairsBuilder::build(ListWidgetInput*input, NameValuePairBlock*pBlock)
    {
        ListWidgetControl* pControl = input->listWidgetControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl, L"pControl is nullptr", L"paramodel", L"2024-02-20");

        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        // Add a Check List.
        ListWidget* pListWidget = nullptr;
        if (nullptr == pBlock)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            pListWidget = m_nvps->addItem<ListWidget>(info);
        }
        else
        {
            pListWidget = pBlock->addItem<ListWidget>(info);
        }
        
        // Initialize the value.
        FOR_EACH(item, pControl->getList())
        {
            gcmp::OwnerPtr<Info> info = NEW_AS_OWNER_PTR(Info, item.get());
            pListWidget->addItem(info);
        }

        pControl->subscribe(pListWidget);
    }

    void NameValuePairsBuilder::build(WidgetAgentValueInput* input, NameValuePairBlock* nvpb)
    {
        WidgetAgentControl* pControl = input->widgetAgentControl();
        DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != pControl,
            L"The control is nullptr", L"paramodel", L"2024-02-20");
        DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != pControl->qtWidget(),
            L"No Qt widget in the WidgetAgentControl", L"paramodel", L"2024-02-20");
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl->info() != nullptr, L"info is null", L"paramodel", L"2024-02-20");
        Info info(pControl->info());

        // Add a widget agent.
        WidgetAgent* widgetAgent = nullptr;
        if (nullptr == nvpb) {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_nvps, L"name value pairs is nullptr", L"paramodel", L"2024-02-20");
            widgetAgent = m_nvps->addItem<WidgetAgent>(info);
        }
        else {
            widgetAgent = nvpb->addItem<WidgetAgent>(info);
        }

        //
        // Initialize the value.
        widgetAgent->setQtWidget(pControl->takeAwayQtWidget());
        widgetAgent->setTransferOwnership(pControl->transferOwnership());
        if (widgetAgent->parent())
        {
            widgetAgent->setQtObjectName(gcmp::StringUtil::ToWString(widgetAgent->parent()->path().str()) + L"/" + info.caption());
        }

        //
        // Subscribe to the widget agent control.
        pControl->subscribe(widgetAgent);
    }
}

namespace gfam
{
    static const std::wstring s_key(L"MultisectionLoftEditModePanel");
    static MultisectionLoftEditModePanel s_MultisectionLoftEditModePanel(gnuf::EItemType::eNameValuePairs);

    static const std::wstring s_guideCurveKey(L"MultisectionLoftGuideCurvePanel");
    static MultisectionLoftGuideCurvePanel s_MultisectionLoftGuideCurvePanel(gnuf::EItemType::eNameValuePairs);

    static const std::wstring s_fittingModeKey(L"MultisectionLoftFittingModePanel");
    static MultisectionLoftFittingModePanel s_MultisectionLoftFittingModePanel(gnuf::EItemType::eNameValuePairs);
}

//_____________________________________________________________________________
// MultisectionLoftEditModePanel class implementation
//
MultisectionLoftEditModePanel::MultisectionLoftEditModePanel(EItemType type)
    : DynamicPanelBase(s_key, gcmp::UniqueString::Find("MultisectionLoftEditModePanel"), L"", false), m_type(type)
{}

MultisectionLoftEditModePanel::~MultisectionLoftEditModePanel()
{}

MultisectionLoftEditModePanel * MultisectionLoftEditModePanel::get()
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(ArrangementAreaContentManager::get() != nullptr, L"ArrangementAreaContentManager::get() is null", L"paramodel", L"2024-02-20");
    return static_cast<MultisectionLoftEditModePanel*>(ArrangementAreaContentManager::get()->contentBy(s_key));
}

void MultisectionLoftEditModePanel::setValueInputSet(gcmp::OwnerPtr<gnuf::ValueInputSet> opValueInputSet)
{
    m_opValueInputSet = TransferOwnership(opValueInputSet);

    Item* item = getItem(EItemType::eNameValuePairs);
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != item, L"Failed to get the item!", L"paramodel", L"2024-02-20");
    NameValuePairs* nvps = item->cast<NameValuePairs>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != nvps, L"Failed to get the name-value pairs!", L"paramodel", L"2024-02-20");
    if(!nvps->contents().empty())
    {
        nvps->clearContents();
    }

    NameValuePairsBuilder(nvps).build(m_opValueInputSet.get());
}

Item* MultisectionLoftEditModePanel::getItem(const EItemType type) const
{
    if (type == m_type &&
        rawToolbar() &&
        rawToolbar()->qtItem() &&
        rawToolbar()->contents().size() == 1 &&
        rawToolbar()->contents().front() &&
        rawToolbar()->contents().front()->type() == type)
    {
        auto item = const_cast<Item*>(rawToolbar()->contents().front().get());
        return item;
    }
    return nullptr;
}

void MultisectionLoftEditModePanel::initialize(Toolbar* toolbar)
{
    toolbar->setEventHandler(this);

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        toolbar->setAppearanceSetting(NEW_AS_OWNER_PTR(
            AppearanceSetting, AppearanceSetting::EStyle::eNameValuePairs));
        toolbar->tweakAppearanceSetting([](AppearanceSetting* setting)->void
        {
            NameValuePairsAppearanceSetting& nameValuePairsSetting = setting->nameValuePairsAppearanceSetting();
            nameValuePairsSetting.setRowMinimumHeight(32);
            nameValuePairsSetting.setGroupSpacing(0);
        });

        toolbar->addItem<NameValuePairs>();
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
}

gcmp::OwnerPtr<QtToolbar> MultisectionLoftEditModePanel::createQtToolBar(Toolbar* toolbar)
{
    gcmp::OwnerPtr<QtToolbar> qtToolBar;

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        qtToolBar = NEW_AS_OWNER_PTR(QtToolbar, toolbar, Direction::Vertical);
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
    return TransferOwnership(qtToolBar);
}

void MultisectionLoftEditModePanel::onHovered(Item * item, bool hovered, void * qtWgt)
{
    showBalloon(item, hovered, qtWgt);
}

void MultisectionLoftEditModePanel::onEvent(ArrangementAreaEvent* evt)
{
    switch (evt->type())
    {
    case ArrangementAreaEvent::EType::ePreferencesChanged:
        auto theEvt = static_cast<PreferencesChangedAreaEvent*>(evt);
        const Preferences* preferences = theEvt->preferences();
        DBG_WARN_AND_RETURN_VOID_UNLESS(preferences, L"preferences is nullptr", L"paramodel", L"2024-02-20");

        if (const auto* entry = preferences->changedEntryBy(PreferenceEntry::eTheme))
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
            m_pallet->refresh();
        }
        break;
    }
    Component::onEvent(evt);
}

QWidget* MultisectionLoftEditModePanel::qtWidget()
{
    if (nullptr != m_pallet && nullptr != m_pallet->qtWidget()) {
        return m_pallet->qtWidget();
    }
    return nullptr;
}

void MultisectionLoftEditModePanel::onPostOpacityChanged()
{
    if (qtWidget()) {
        DBG_WARN_AND_RETURN_VOID_UNLESS(arrangementArea(), L"arrangementArea() is nullptr", L"paramodel", L"2024-02-20");
        qtWidget()->setWindowOpacity(arrangementArea()->opacity());
    }
}

void MultisectionLoftEditModePanel::onPostConnectedWithArrangementArea()
{
    Component::onPostConnectedWithArrangementArea();

    m_pallet = NEW_AS_OWNER_PTR(Pallet, arrangementArea());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->rHeader().caption = GBMP_TR(L"多截面放样体");  // 多截面放样体对话框

    m_pallet->rHeader().wantBackground = true;
    m_pallet->rHeader().canDragAndMove = false;
    m_pallet->setWantBorder(true);
    DBG_WARN_AND_RETURN_VOID_UNLESS(rawToolbar(), L"rawToolbar() is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->setQtContent(rawToolbar()->qtItem());
    m_pallet->show();

    Utility::setQtWidgetParent(this);
}

void MultisectionLoftEditModePanel::onPreDisconnectedFromArrangementArea()
{
    Component::onPreDisconnectedFromArrangementArea();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->hide(true);
    m_pallet.reset(nullptr);
}

bool MultisectionLoftEditModePanel::clearEditModePanel(const bool wantToRecreate)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arrangementArea(), L"arrangementArea() is nullptr", L"paramodel", L"2024-02-20");

    ArrangementArea* prevArea = nullptr;

    // Remove the arrangement area.
    if (ArrangementArea* area = arrangementArea()) 
    {
        arrangementArea()->removeArrangementArea(area);
    }

    // Create a new arrangement area, if needed.
    if (wantToRecreate)
    {
        // Create a new arrangement area and connect with the dynamic panel
        ArrangementArea * newArea = arrangementArea()->addArrangementArea(ELayoutPattern::eFill);
        newArea->setArrangementAreaContent(this);

        if (nullptr == prevArea)
        {
            int areaIndex = arrangementArea()->positionForDynamicPanels() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
        else
        {
            // Behind previous dynamic panel.
            int areaIndex = prevArea->index() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
    }

    return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
MultisectionLoftGuideCurvePanel::MultisectionLoftGuideCurvePanel(EItemType type)
    : DynamicPanelBase(s_guideCurveKey, gcmp::UniqueString::Find("MultisectionLoftGuideCurvePanel"), L"", false), m_type(type)
{}

MultisectionLoftGuideCurvePanel::~MultisectionLoftGuideCurvePanel()
{}

MultisectionLoftGuideCurvePanel * MultisectionLoftGuideCurvePanel::get()
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(ArrangementAreaContentManager::get() != nullptr, L"ArrangementAreaContentManager::get() is null", L"paramodel", L"2024-02-20");
    return static_cast<MultisectionLoftGuideCurvePanel*>(ArrangementAreaContentManager::get()->contentBy(s_guideCurveKey));
}

void MultisectionLoftGuideCurvePanel::setValueInputSet(gcmp::OwnerPtr<gnuf::ValueInputSet> opValueInputSet)
{
    m_opValueInputSet = TransferOwnership(opValueInputSet);

    Item* item = getItem(EItemType::eNameValuePairs);
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != item, L"Failed to get the item!", L"paramodel", L"2024-02-20");
    NameValuePairs* nvps = item->cast<NameValuePairs>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != nvps, L"Failed to get the name-value pairs!", L"paramodel", L"2024-02-20");
    if (!nvps->contents().empty())
    {
        nvps->clearContents();
    }

    NameValuePairsBuilder(nvps).build(m_opValueInputSet.get());
}

Item* MultisectionLoftGuideCurvePanel::getItem(const EItemType type) const
{
    if (type == m_type &&
        rawToolbar() &&
        rawToolbar()->qtItem() &&
        rawToolbar()->contents().size() == 1 &&
        rawToolbar()->contents().front() &&
        rawToolbar()->contents().front()->type() == type)
    {
        auto item = const_cast<Item*>(rawToolbar()->contents().front().get());
        return item;
    }
    return nullptr;
}

void MultisectionLoftGuideCurvePanel::initialize(Toolbar* toolbar)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(toolbar, L"toolbar is nullptr", L"paramodel", L"2024-02-20");
    toolbar->setEventHandler(this);

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        toolbar->setAppearanceSetting(NEW_AS_OWNER_PTR(
            AppearanceSetting, AppearanceSetting::EStyle::eNameValuePairs));
        toolbar->tweakAppearanceSetting([](AppearanceSetting* setting)->void
        {
            NameValuePairsAppearanceSetting& nameValuePairsSetting = setting->nameValuePairsAppearanceSetting();
            nameValuePairsSetting.setRowMinimumHeight(32);
            nameValuePairsSetting.setGroupSpacing(0);
        });

        toolbar->addItem<NameValuePairs>();
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
}

gcmp::OwnerPtr<QtToolbar> MultisectionLoftGuideCurvePanel::createQtToolBar(Toolbar* toolbar)
{
    gcmp::OwnerPtr<QtToolbar> qtToolBar;

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        qtToolBar = NEW_AS_OWNER_PTR(QtToolbar, toolbar, Direction::Vertical);
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
    return TransferOwnership(qtToolBar);
}

void MultisectionLoftGuideCurvePanel::onHovered(Item * item, bool hovered, void * qtWgt)
{
    showBalloon(item, hovered, qtWgt);
}

void MultisectionLoftGuideCurvePanel::onEvent(ArrangementAreaEvent* evt)
{
    switch (evt->type())
    {
    case ArrangementAreaEvent::EType::ePreferencesChanged:
        auto theEvt = static_cast<PreferencesChangedAreaEvent*>(evt);
        const Preferences* preferences = theEvt->preferences();
        DBG_WARN_AND_RETURN_VOID_UNLESS(preferences, L"preferences is nullptr", L"paramodel", L"2024-02-20");

        if (const auto* entry = preferences->changedEntryBy(PreferenceEntry::eTheme))
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
            m_pallet->refresh();
        }
        break;
    }
    Component::onEvent(evt);
}

QWidget* MultisectionLoftGuideCurvePanel::qtWidget()
{
    if (nullptr != m_pallet && nullptr != m_pallet->qtWidget()) {
        return m_pallet->qtWidget();
    }
    return nullptr;
}

void MultisectionLoftGuideCurvePanel::onPostOpacityChanged()
{
    if (qtWidget()) {
        DBG_WARN_AND_RETURN_VOID_UNLESS(arrangementArea(), L"arrangementArea() is nullptr", L"paramodel", L"2024-02-20");
        qtWidget()->setWindowOpacity(arrangementArea()->opacity());
    }
}

void MultisectionLoftGuideCurvePanel::onPostConnectedWithArrangementArea()
{
    Component::onPostConnectedWithArrangementArea();

    m_pallet = NEW_AS_OWNER_PTR(Pallet, arrangementArea());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->rHeader().caption = GBMP_TR(L"多截面放样体");  // 多截面放样体对话框

    m_pallet->rHeader().wantBackground = true;
    m_pallet->rHeader().canDragAndMove = false;
    m_pallet->setWantBorder(true);
    DBG_WARN_AND_RETURN_VOID_UNLESS(rawToolbar(), L"rawToolbar() is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->setQtContent(rawToolbar()->qtItem());
    m_pallet->show();

    Utility::setQtWidgetParent(this);
}

void MultisectionLoftGuideCurvePanel::onPreDisconnectedFromArrangementArea()
{
    Component::onPreDisconnectedFromArrangementArea();

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->hide(true);
    m_pallet.reset(nullptr);
}

bool MultisectionLoftGuideCurvePanel::clearEditModePanel(const bool wantToRecreate)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arrangementArea(), L"arrangementArea() is nullptr", L"paramodel", L"2024-02-20");

    ArrangementArea* prevArea = nullptr;

    // Remove the arrangement area.
    if (ArrangementArea* area = arrangementArea())
    {
        arrangementArea()->removeArrangementArea(area);
    }

    // Create a new arrangement area, if needed.
    if (wantToRecreate)
    {
        // Create a new arrangement area and connect with the dynamic panel
        ArrangementArea * newArea = arrangementArea()->addArrangementArea(ELayoutPattern::eFill);
        newArea->setArrangementAreaContent(this);

        if (nullptr == prevArea)
        {
            int areaIndex = arrangementArea()->positionForDynamicPanels() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
        else
        {
            // Behind previous dynamic panel.
            int areaIndex = prevArea->index() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
    }

    return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
MultisectionLoftFittingModePanel::MultisectionLoftFittingModePanel(EItemType type)
    : DynamicPanelBase(s_fittingModeKey, gcmp::UniqueString::Find("MultisectionLoftFittingModePanel"), L"", false), m_type(type)
{}

MultisectionLoftFittingModePanel::~MultisectionLoftFittingModePanel()
{}

MultisectionLoftFittingModePanel * MultisectionLoftFittingModePanel::get()
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(ArrangementAreaContentManager::get() != nullptr, L"ArrangementAreaContentManager::get() is null", L"paramodel", L"2024-02-20");
    return static_cast<MultisectionLoftFittingModePanel*>(ArrangementAreaContentManager::get()->contentBy(s_fittingModeKey));
}

void MultisectionLoftFittingModePanel::setValueInputSet(gcmp::OwnerPtr<gnuf::ValueInputSet> opValueInputSet)
{
    m_opValueInputSet = TransferOwnership(opValueInputSet);

    Item* item = getItem(EItemType::eNameValuePairs);
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != item, L"Failed to get the item!", L"paramodel", L"2024-02-20");
    NameValuePairs* nvps = item->cast<NameValuePairs>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != nvps, L"Failed to get the name-value pairs!", L"paramodel", L"2024-02-20");
    if (!nvps->contents().empty())
    {
        nvps->clearContents();
    }

    NameValuePairsBuilder(nvps).build(m_opValueInputSet.get());
}

Item* MultisectionLoftFittingModePanel::getItem(const EItemType type) const
{
    if (type == m_type &&
        rawToolbar() &&
        rawToolbar()->qtItem() &&
        rawToolbar()->contents().size() == 1 &&
        rawToolbar()->contents().front() &&
        rawToolbar()->contents().front()->type() == type)
    {
        auto item = const_cast<Item*>(rawToolbar()->contents().front().get());
        return item;
    }
    return nullptr;
}

void MultisectionLoftFittingModePanel::initialize(Toolbar* toolbar)
{
    toolbar->setEventHandler(this);

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        toolbar->setAppearanceSetting(NEW_AS_OWNER_PTR(
            AppearanceSetting, AppearanceSetting::EStyle::eNameValuePairs));
        toolbar->tweakAppearanceSetting([](AppearanceSetting* setting)->void
        {
            NameValuePairsAppearanceSetting& nameValuePairsSetting = setting->nameValuePairsAppearanceSetting();
            nameValuePairsSetting.setRowMinimumHeight(32);
            nameValuePairsSetting.setGroupSpacing(0);
        });

        toolbar->addItem<NameValuePairs>();
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
}

gcmp::OwnerPtr<QtToolbar> MultisectionLoftFittingModePanel::createQtToolBar(Toolbar* toolbar)
{
    gcmp::OwnerPtr<QtToolbar> qtToolBar;

    switch (m_type) {
    case EItemType::eNameValuePairs:
    {
        qtToolBar = NEW_AS_OWNER_PTR(QtToolbar, toolbar, Direction::Vertical);
    } break;

    default:
        DBG_WARN(L"Don't support this type of item!", L"paramodel", L"2024-02-20");
    }
    return TransferOwnership(qtToolBar);
}

void MultisectionLoftFittingModePanel::onHovered(Item * item, bool hovered, void * qtWgt)
{
    showBalloon(item, hovered, qtWgt);
}

void MultisectionLoftFittingModePanel::onEvent(ArrangementAreaEvent* evt)
{
    switch (evt->type())
    {
    case ArrangementAreaEvent::EType::ePreferencesChanged:
        auto theEvt = static_cast<PreferencesChangedAreaEvent*>(evt);
        const Preferences* preferences = theEvt->preferences();
        DBG_WARN_AND_RETURN_VOID_UNLESS(preferences, L"preferences is nullptr", L"paramodel", L"2024-02-20");

        if (const auto* entry = preferences->changedEntryBy(PreferenceEntry::eTheme))
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
            m_pallet->refresh();
        }
        break;
    }
    Component::onEvent(evt);
}

QWidget* MultisectionLoftFittingModePanel::qtWidget()
{
    if (nullptr != m_pallet && nullptr != m_pallet->qtWidget()) {
        return m_pallet->qtWidget();
    }
    return nullptr;
}

void MultisectionLoftFittingModePanel::onPostOpacityChanged()
{
    if (qtWidget()) {
        qtWidget()->setWindowOpacity(arrangementArea()->opacity());
    }
}

void MultisectionLoftFittingModePanel::onPostConnectedWithArrangementArea()
{
    Component::onPostConnectedWithArrangementArea();

    m_pallet = NEW_AS_OWNER_PTR(Pallet, arrangementArea());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->rHeader().caption = GBMP_TR(L"多截面放样体");  // 多截面放样体对话框

    m_pallet->rHeader().wantBackground = true;
    m_pallet->rHeader().canDragAndMove = false;
    m_pallet->setWantBorder(true);
    DBG_WARN_AND_RETURN_VOID_UNLESS(rawToolbar(), L"rawToolbar() is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->setQtContent(rawToolbar()->qtItem());
    m_pallet->show();

    Utility::setQtWidgetParent(this);
}

void MultisectionLoftFittingModePanel::onPreDisconnectedFromArrangementArea()
{
    Component::onPreDisconnectedFromArrangementArea();

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pallet, L"m_pallet is nullptr", L"paramodel", L"2024-02-20");
    m_pallet->hide(true);
    m_pallet.reset(nullptr);
}

bool MultisectionLoftFittingModePanel::clearEditModePanel(const bool wantToRecreate)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(arrangementArea(), L"arrangementArea() is nullptr", L"paramodel", L"2024-02-20");

    ArrangementArea* prevArea = nullptr;

    // Remove the arrangement area.
    if (ArrangementArea* area = arrangementArea())
    {
        arrangementArea()->removeArrangementArea(area);
    }

    // Create a new arrangement area, if needed.
    if (wantToRecreate)
    {
        // Create a new arrangement area and connect with the dynamic panel
        ArrangementArea * newArea = arrangementArea()->addArrangementArea(ELayoutPattern::eFill);
        newArea->setArrangementAreaContent(this);

        if (nullptr == prevArea)
        {
            int areaIndex = arrangementArea()->positionForDynamicPanels() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
        else
        {
            // Behind previous dynamic panel.
            int areaIndex = prevArea->index() + 1;
            ArrangementArea::moveArrangementArea(newArea, arrangementArea(), areaIndex);
        }
    }

    return true;
}